﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;

namespace MathLib.Controls
{
    // Many thanks to the guy from http://www.freshnova.com/C-Tutorials/superscript-subscript-label.html
    // whose site has now disappeared for some reason
    public class MathLabel : Label
    {
        // Fields
        private char[] chrs;
        private IContainer components;
        private string norm = string.Empty;
        private string sub = string.Empty;
        private Font subscriptFont;
        private char subscriptMark = '`';
        private string sup = string.Empty;
        private Font superscriptFont;
        private char superscriptMark = '^';
        private float width;

        // Methods
        public MathLabel()
        {
            this.InitializeComponent();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (this.components != null))
            {
                this.components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.components = new Container();
            this.subscriptFont = new Font("Microsoft Sans Serif", (this.Font.Size / 2f) + 2.5f, FontStyle.Regular, GraphicsUnit.Point);
            this.superscriptFont = new Font("Microsoft Sans Serif", (this.Font.Size / 2f) + 2.5f, FontStyle.Regular, GraphicsUnit.Point);
        }

        private float MeasureDSW(Graphics graphics, string text, Font font)
        {
            float num = 0f;
            StringFormat stringFormat = new StringFormat();
            RectangleF layoutRect = new RectangleF(0f, 0f, 100f, 100f);
            CharacterRange[] ranges = new CharacterRange[] { new CharacterRange(0, text.Length) };
            stringFormat.SetMeasurableCharacterRanges(ranges);
            foreach (Region region in graphics.MeasureCharacterRanges(text, font, layoutRect, stringFormat))
            {
                layoutRect = region.GetBounds(graphics);
                num += layoutRect.Right;
            }
            return num;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            this.width = 0f;
            this.AutoSize = false;
            SolidBrush brush = new SolidBrush(Color.Black);
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            this.chrs = this.Text.ToCharArray();
            int index = 0;
            while (index < (this.chrs.Length - 1))
            {
                try
                {
                    if (this.chrs[index].Equals(this.subscriptMark))
                    {
                        index = this.ProcessSubscriptText(index + 1);
                        if (!string.IsNullOrEmpty(this.sub))
                        {
                            e.Graphics.DrawString(this.sub, this.subscriptFont, brush, (float)(this.width - 0.3f), (float)5f);
                            this.width += this.MeasureDSW(e.Graphics, this.sub, this.subscriptFont);
                            this.sub = string.Empty;
                        }
                    }
                    else if (this.chrs[index].Equals(this.superscriptMark))
                    {
                        index = this.ProcessSuperscriptText(index + 1);
                        e.Graphics.DrawString(this.sup, this.superscriptFont, brush, (float)(this.width - 0.3f), (float)-1f);
                        this.width += this.MeasureDSW(e.Graphics, this.sup, this.superscriptFont);
                        this.sup = string.Empty;
                    }
                    else
                    {
                        index = this.ProcessNormalText(index);
                        if (!string.IsNullOrEmpty(this.norm))
                        {
                            e.Graphics.DrawString(this.norm, this.Font, brush, this.width, 2f);
                            this.width += this.MeasureDSW(e.Graphics, this.norm, this.Font);
                            this.norm = string.Empty;
                        }
                    }
                    continue;
                }
                catch (Exception)
                {
                    e.Graphics.DrawString(this.Text, this.Font, brush, this.width, 2f);
                    this.width += this.MeasureDSW(e.Graphics, this.Text, this.Font);
                    continue;
                }
            }
        }

        private int ProcessNormalText(int i)
        {
            while (((i <= (this.chrs.Length - 1)) && (this.chrs[i] != this.subscriptMark)) && (this.chrs[i] != this.superscriptMark))
            {
                this.norm = this.norm + this.chrs[i];
                i++;
            }
            return i;
        }

        private int ProcessSubscriptText(int i)
        {
            while ((i <= (this.chrs.Length - 1)) && (this.chrs[i] != this.subscriptMark))
            {
                this.sub = this.sub + this.chrs[i];
                i++;
            }
            return (i + 1);
        }

        private int ProcessSuperscriptText(int i)
        {
            while ((i <= (this.chrs.Length - 1)) && (this.chrs[i] != this.superscriptMark))
            {
                this.sup = this.sup + this.chrs[i];
                i++;
            }
            return (i + 1);
        }

        // Properties
        [Description("Font of the subscript text."), Category("Appearance")]
        public Font SubscriptFont
        {
            get
            {
                return this.subscriptFont;
            }
            set
            {
                this.subscriptFont = value;
                base.Invalidate();
            }
        }

        [Description("Marker for start/end of subscript text."), Category("Appearance")]
        public char SubscriptMarker
        {
            get
            {
                return this.subscriptMark;
            }
            set
            {
                this.subscriptMark = value;
                base.Invalidate();
            }
        }

        [Description("Font of superscript text."), Category("Appearance")]
        public Font SuperscriptFont
        {
            get
            {
                return this.superscriptFont;
            }
            set
            {
                this.superscriptFont = value;
                base.Invalidate();
            }
        }

        [Category("Appearance"), Description("Marker for start/end of superscript text.")]
        public char SuperscriptMarker
        {
            get
            {
                return this.superscriptMark;
            }
            set
            {
                this.superscriptMark = value;
                base.Invalidate();
            }
        }
    }
}